local nl = require'luaNumeric'
require 'luaFDTD3D'
local plot = require "Q2DViewerEx"
require "Q3DViewer"

--=====================================================================--
--初始化参数
local NFPostView={
	funs = {};
	xAxis = 0;
	ytype = 1;
	xtype = 1;
	fields_type = scalar_e;
	plot_mode = 1;
	nor2port_state = 0;
	nor2port_power = 1.0;
	range_min = 0.0;
	range_max = 1.0;
	range_min_ui = 0.0;
	range_max_ui = 1.0;
	auto_range = true;
	colormap = 'Jet';
	unit_type = 0;
	show3D = true;
	show2DSlice = false;
	show_mesh = false;
	field_scale = 1.0;
	range = {0,2};
	freq_index = 0;
	scale_type = 1;
};
--=====================================================================--

--=====================================================================--
--创建表和创建元表
function NFPostView:new (o)
	o = o or {};
	self.__index = self;
	setmetatable(o,self)
	o:init();
	return o;
end
--=====================================================================--


--=====================================================================--
--UI函数，会在主程序里覆盖
--输入参数为字符串：’Jet', 'JetJet'
function NFPostView:update_colormap_to_ui(name)
end
--=====================================================================--

--=====================================================================--
--UI函数，会在主程序里覆盖
--输入参数为bool：true or false
function NFPostView:update_autorange_to_ui(set)
end
--=====================================================================--

--=====================================================================--
--UI函数，会在主程序里覆盖
--输入参数为number
function NFPostView:update_range_to_ui()
end
--=====================================================================--

--=====================================================================--
--UI函数，会在主程序里覆盖
--输入参数为number
function NFPostView:update_plot_mode_to_ui(ft,mode)
end
--=====================================================================--

--=====================================================================--
--UI函数，会在主程序里覆盖
--输入参数为number
function NFPostView:update_fields_type_to_ui(ft)

end
--=====================================================================--

--=====================================================================--
--更新数据
function NFPostView:update_data ()
	print( 'update data' )
	assert( self.probe, 'Probe为空' ) 
	self.fields =  self.probe:fields_obj(); --实际在c++程序里更新
	assert( self.fields, 'Fields为空' ) 	
	self:update_fields_to_view()
end
--=====================================================================--

--=====================================================================--
--更新数据
function NFPostView:refresh_figs ()
	print( 'update data' )
	assert( self.probe, 'Probe为空' ) 
	self.fields =  self.probe:fields_obj(); --实际在c++程序里更新
	self:update_fields_to_view()
end
--=====================================================================--

--=====================================================================--
--更新数据
function NFPostView:update_ids ()
	assert( self.probe, 'Probe为空' ) 
	local  freq = self.probe:freq();
	local nfreq = #freq;
	local fts = self.probe:fields_types();
	local ft2idx={};
	local ids = nl.new_ivector();
	local freq_index = self.freq_index;
	for k,v in pairs(fts) do 
		ft2idx[v] =  k;
	end
	
	local fields_type=self.fields_type;
	if fields_type <= hz and fields_type >=ex then
		local ftidx = ft2idx[fields_type]  or 0;
		ids:add(  freq_index + nfreq*(ftidx-1) );
	end
	if fields_type == hz+1 then 
		for ii=ex,ex+3 do 
			if ft2idx[ii] ~= nil then 
				local ftidx = ft2idx[ii];
				ids:add(  freq_index + nfreq*(ftidx-1) );
				--print('ftidx:',ftidx)
			end	
		end
	end
	if fields_type == hz+2 then 
		for ii=hx,hx+3 do 
			if ft2idx[ii] ~= nil then 
				local ftidx = ft2idx[ii];
				ids:add(  freq_index + nfreq*(ftidx-1) );
			end	
		end
	end
	self.ids = ids;
	--print_table( ft2idx);
	--print( ids ,freq_index,fts);
end
--=====================================================================--

--=====================================================================--
function NFPostView:get_colormap_str ()
	
	local str_ft = 'H';
	local str_ft_unit = 'A/m';
	if self.fields_type < hx or self.fields_type == scalar_e then str_ft = 'E' ; str_ft_unit = 'V/m'; end;
	local str = '';

	if self.scale_type == 0 then
		str = str_ft..' (dB'..str_ft_unit..')';
	elseif self.scale_type == 1 then
		str = str_ft..' ('..str_ft_unit..')';
	elseif self.scale_type == 2 then
		str = 'Arg (' .. str_ft..') (arc.)';
	elseif self.scale_type == 3 then
		str = 'Real (' .. str_ft..') ('..str_ft_unit..')';
	elseif self.scale_type == 4 then
		str = 'Imag (' .. str_ft..') ('..str_ft_unit..')';
	end

	return str;
end

function NFPostView:get_info_str ()
	local str = self:get_colormap_str();
	assert( self.probe, 'Probe为空' ) 
	self.freq = self.probe:freq();
	if self.unit_type==0 then
		str = str .. ' @ Frequency: ' .. self.freq[ self.freq_index  + 1] .. ' ' .. Geometry.ref_units_freq_str();
	else
		local wavelength = c0 / self.freq[ self.freq_index  + 1] / Geometry.ref_units_dim()  / Geometry.ref_units_freq();
		str = str .. ' @ Wavelength: ' .. wavelength .. ' ' .. Geometry.ref_units_dim_str();
	end
	return str;
end
--=====================================================================--

--=====================================================================--
--输入参数为字符串
function NFPostView:change_colormap(str)
	if self.colormap ~= str then 
		self.colormap = str;
		self:update_colormap_to_ui(str);
		self:update_colormap_str_to_view();
		self:update_info_str_to_view();
		self:update_view();
	end
end
--=====================================================================--

--=====================================================================--
function NFPostView:get_scale_power()
	if self.nor2port_state == 0 then return 1 end;
	print(self.freq,self.p1 )
	local ptotal = nl.interpolation(self.freq,self.p1,self.freq[ self.freq_index +1]);
	local pout = nl.interpolation(self.freq,self.p2,self.freq[ self.freq_index +1]);
	if self.nor2port_state == 1 then
		return self.nor2port_power / pout; 
	end;
	if self.nor2port_state == 2 then
		return self.nor2port_power / ptotal; 
	end;	
	return 1;
end
--=====================================================================--

--=====================================================================--
function NFPostView:get_source_power ()
	assert( self.probe, 'Probe为空' ) 
	self.p1 = nl.new_vector();
	self.p2 = nl.new_vector();
	self.freq = self.probe:freq();
	for k,v in pairs(self.freq) do 
		d1,d2 = Gallop.FDTDSolver:get_all_lumpedsrc_ports_power(v);		
		self.p1:add(d1);
		self.p2:add(d2);		
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为字符串
function NFPostView:change_nor2port(type,power)
	if self.nor2port_state ~= type or self.nor2port_power ~= power then 
		print(type,power)
		self.nor2port_state = type 
		self.nor2port_power = power
		self:update_nor2port_state_to_ui();
		--self:update_parameters_to_ui();		
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_fieldstype(ft)
	if self.fields_type ~= ft then
		self.fields_type = ft;
		self:update_selection();
		self:update_range();
		self:update_colormap_str_to_view();
		self:update_info_str_to_view();
		self:update_view();
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_scale_type(ft)
	if self.scale_type ~= ft then
		self.scale_type = ft;
		self:update_selection();
		self:update_range();
		self:update_colormap_str_to_view();
		self:update_info_str_to_view();
		self:update_view();
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_show3D(s)
	if self.show3D ~= s then
		self.show3D = s;
		self:update_view();
		self:update_graph_settings_to_ui();
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_show2DSlice(s)
	if self.show2DSlice ~= s then
		self.show2DSlice = s;
		if s==true then 
			local bbox = self.probe:bbox();
			if bbox:xsize() < 1e-6 then 
				self:generate_slice(yz,bbox:xcenter()) ;
			end
			if bbox:ysize() < 1e-6 then 
				self:generate_slice(zx,bbox:ycenter()) ;
			end
			if bbox:zsize() < 1e-6 then 
				self:generate_slice(xy,bbox:zcenter()) ;
			end
		end
		self:update_view();
		self:update_graph_settings_to_ui();
	end
end

function NFPostView:generate_slice(pln, pos)
	if pln ~= self.pln or pos ~= self.pos then 
		self.pln = pln;
		self.pos = pos;
		self.slice = self:generate_slice_impl(pln, pos);
		--self.slice =Geometry.GetGeometry():gen_slice(pln,pos) 
		self.slice:outline_width(3)
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_showmesh(s)
	if self.show_mesh ~= s then
		self.show_mesh = s;
		self.fields:is_outline(s);
		self:update_view();
		self:update_graph_settings_to_ui();
	end
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_units_type(s)
	if self.unit_type ~= s then
		self.unit_type = s;
		self:update_info_str_to_view();
		self:update_view();
	end
end
--=====================================================================--

function NFPostView:update_info ()
	--if self.probe then
		local name = self.probe:name();
		return name;
	--end
	--return '';
end


--=====================================================================--
--更新颜色条取值范围
function NFPostView:change_range_min ( v )
	self.range[1] = v
	self:update_range();
	self:update_view();
end
function NFPostView:change_range_max ( v )
	self.range[2] = v
	self:update_range();
	self:update_view();
end
function NFPostView:change_range ( v1,v2 )
	self.range = {v1,v2}
	self:update_range();
	self:update_view();
end
--=====================================================================--

--=====================================================================--
--更新画图函数
function NFPostView:update_range()
	if self.fields and self.auto_range then
		self.range = { self.fields:value_range() };
	end
	self:update_range_to_ui(self.auto_range,self.range[1],self.range[2]);
	--self:update_view()
end
--=====================================================================--

--=====================================================================--
--自动更新颜色条取值范围
function NFPostView:refresh_range ()
	if self.fields then		
		self.range = { self.fields:value_range() };
	end
	self:update_range();
	self:update_view()
end
--=====================================================================--

--=====================================================================--
--输入参数为数值
function NFPostView:change_auto_range(set)
	if self.auto_range ~= set  then
		self.auto_range = set;
		self:update_range();
		self:update_view()
	end
end
--=====================================================================--

--=====================================================================--
--创建表和创建元表
function NFPostView:init ()
	self.funs = {};
	self.funs.abs = function(input) return nl.abs(input); end;
	self.funs.phs = function(input) return nl.arg(input)*180/pi; end;
	self.funs.real = function(input) return nl.real(input); end;
	self.funs.imag = function(input) return nl.imag(input); end;
	self.funs.log = function(input) 
		local  d = nl.abs(input);
		d = 20* nl.log10(d)
		return d; 
	end;
	self.fun_names = {};
	self.fun_names[1] = 'log';
	self.fun_names[2] = 'abs';
	self.fun_names[3] = 'phs';
	self.fun_names[4] = 'real';
	self.fun_names[5] = 'imag';
	self.fun_names[6] = 'square';	
	
	self.ft_names = {};
	self.ft_names[1] = 'Ex';
	self.ft_names[2] = 'Ey';
	self.ft_names[3] = 'Ez';
	self.ft_names[4] = 'Hx';
	self.ft_names[5] = 'Hy';
	self.ft_names[6] = 'Hz';
	self.ft_names[7] = 'E';
	self.ft_names[8] = 'H';

	self.ytype = 1;
end
--=====================================================================--

--=====================================================================--
--画图函数
function NFPostView:render ()
	if self.slice and self.show2DSlice then 
		self.slice:Draw() 
	end
end
--=====================================================================--

--=====================================================================--
--保存动图
function NFPostView:export_animate_fields_figs (path)
	local num = 30;
	local dphs = 2*pi/num
	for ii = 0,num-1 do 
		self:update_phase_to_view( ii *dphs );
		self:update_view();
		self:save_png(path..'/fields-'..string.format("%03d", ii)..'.png');
	end

	os.execute(  ' magick -loop 0 -delay 20 ' .. path .. '/fields-*.png '
				..  path .. '/fig.gif' )
				
end
--=====================================================================--

--=====================================================================--
--保存
function NFPostView:export_fig (path,ft,mode)
	self:save_png(path..'/fields-'..self.ft_names[ft+1]..'-'..self.fun_names[mode+1]..'.png');
end
function NFPostView:export_all_figs (path)
	local fts = self:get_fields_types();
	print(fts)
	local arr = {}
	for k,v in pairs(fts) do
		arr[v] = true;
	end
	for k,v in pairs(arr) do
		for ii=0,5 do
			self:update_plot_mode_to_ui(k,ii);
			self:export_fig( path,k,ii);
		end
	end
	
	local mode = {0,1,3,4,5};
	if arr[0] or arr[1] or arr[2] then
		for kk,vv in pairs(mode) do
			self:update_plot_mode_to_ui(6,vv);
			self:export_fig( path,6,vv);

		end
	end
	if arr[3] or arr[4] or arr[5] then
		for kk,vv in pairs(mode) do
			self:update_plot_mode_to_ui(7,vv);
			self:export_fig( path,7,vv);
		end
	end
end
--=====================================================================--

--=====================================================================--
--查看数据
function NFPostView:view_data ()
	if self.fields then	
		local data = self.fields:get_fields()		
		self.dataView  = Gallop.DataPost:create_data_table_to_ui();
		self.dataView:set_data(data);
		
		local header = nl.new_svector();
		header:add('x [mm]')
		header:add('y [mm]')
		header:add('z [mm]')
		header:add(self:get_info_str())	
		self.dataView:set_header(header);
	end
end
--=====================================================================--

return NFPostView;
